///////////////////////////////////////////////////////////////////////////////////////////////////////////////
//	File	:	"CObjectFactory.h"
//
//	Author	:	Travis Setz (TS)
//
//	Purpose	:	The header file for the template class object factory which is used to create
//				the game objects using function pointers
///////////////////////////////////////////////////////////////////////////////////////////////////////////////

#pragma once

#include <map>
using std::map;

template<typename ClassIDType, typename BaseClassType>
class CObjectFactory
{
private:

	typedef BaseClassType* (*ObjectMaker)(void);

	map<ClassIDType, ObjectMaker> m_ObjectMakers;

	static CObjectFactory<ClassIDType, BaseClassType> sm_Instance;

	CObjectFactory(void) {}
	CObjectFactory(const CObjectFactory&);
	CObjectFactory& operator=(const CObjectFactory&);
	~CObjectFactory(void) {}

	template<typename DerivedClassType>
	static BaseClassType* MakeObject(void)
	{
		return new DerivedClassType;
	}

public:
////////////////////////////////////////////////////////
//	Function:	"GetInstance"
//	Last Modified: August 17, 2008
//	Purpose:	To return the singleton's instance.
////////////////////////////////////////////////////////
	static CObjectFactory<ClassIDType, BaseClassType>* GetInstance(void)
	{
		return &sm_Instance;
	}

////////////////////////////////////////////////////////
//	Function:	"RegisterClassType"
//	Last Modified: August 17, 2008
//	Purpose:	Register a class object to be able to be made by the factory.
////////////////////////////////////////////////////////
	template<typename DerivedClassType>
	bool RegisterClassType(ClassIDType id)
	{
		std::pair<ClassIDType, ObjectMaker> objTypeDef;

		objTypeDef.first	=	id;
		objTypeDef.second	=	MakeObject<DerivedClassType>;

		m_ObjectMakers.insert(objTypeDef);

		return true;
	}
////////////////////////////////////////////////////////
//	Function:	"UnregisterClassType"
//	Last Modified: August 17, 2008
//	Purpose:	Unregister a class to stop the factory from being able to create that type.
////////////////////////////////////////////////////////
	bool UnregisterClassType(ClassIDType id)
	{
		map<ClassIDType, ObjectMaker>::iterator iter = m_ObjectMakers.find(id);

		if (iter == m_ObjectMakers.end())
			return false;

		m_ObjectMakers.erase(iter);

		return true;
	}
////////////////////////////////////////////////////////
//	Function:	"CreateObject"
//	Last Modified: August 17, 2008
//	Purpose:	Creates an object of the passed in class type.
////////////////////////////////////////////////////////
	BaseClassType* CreateObject(ClassIDType id)
	{
		map<ClassIDType, ObjectMaker>::iterator iter = m_ObjectMakers.find(id);

		if (iter == m_ObjectMakers.end())
			return NULL;

		return (*iter).second();
	}
////////////////////////////////////////////////////////
//	Function:	"ShutdownObjectFactory"
//	Last Modified: August 17, 2008
//	Purpose:	Shutdown the object factory.
////////////////////////////////////////////////////////
	void ShutdownObjectFactory(void)
	{
		m_ObjectMakers.clear();
	}
};

//declaring on a global scale to allow access
template<typename ClassIDType, typename BaseClassType>
CObjectFactory<ClassIDType, BaseClassType> 
CObjectFactory<ClassIDType, BaseClassType>::sm_Instance;